/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package fr.sonictools.xml;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.xml.bind.JAXBException;
import javax.xml.stream.XMLStreamException;

import fr.sonictools.tools.FileUtils;

/**
 * Class dealing with the xml file. This class allows to convert xml file into
 * java object, and java object into xml file
 * 
 * @author jbenech
 * 
 * @param <T>
 *            type of the requested java object
 */
public class XmlFileHelper<T> {
	private String m_inputXmlFilePath = "";
	private String m_backupXmlFilePath = "";
	private T m_xmlFileObj = null;
	private Boolean m_createBackup = true;
	private Class<T> m_xmlObjClazz = null;
	private JaxbXmlParser<T> m_parser = null;
	private static final Logger LOGGER = Logger.getLogger(XmlFileHelper.class
			.getName());

	/**
	 * Constructor
	 * 
	 * @param xmlFilePath
	 *            path of the xml file to be loaded
	 * @param xmlObjClazz
	 *            Class of the object to deal with
	 * @param createBackup
	 *            Indicates if a backup must be created
	 */
	public XmlFileHelper(String xmlFilePath, Class<T> xmlObjClazz,
			Boolean createBackup) {
		m_inputXmlFilePath = xmlFilePath;
		m_backupXmlFilePath = xmlFilePath + ".bkp";
		m_createBackup = createBackup;
		m_xmlObjClazz = xmlObjClazz;
	}

	/**
	 * Loads the requested xml file into the requested java object <T>
	 * 
	 * @throws JAXBException
	 */
	public T loadXmlFileObject() throws JAXBException, XMLStreamException,
			FileNotFoundException {
		m_xmlFileObj = getJaxbXmlParser().loadObjectUsingStax(
				m_inputXmlFilePath);
		
		return m_xmlFileObj;
	}

	/**
	 * Saves the current java object into the output xml file specified as
	 * parameter
	 * 
	 * @param outputXmlFilePath
	 * @throws JAXBException
	 * @throws XMLStreamException
	 * @throws FileNotFoundException
	 */
	public void saveXmlFileObject(String outputXmlFilePath)
			throws JAXBException, XMLStreamException, FileNotFoundException {

		try {
			createBackupIfRequested();
			getJaxbXmlParser().storeObjectUsingStax(m_xmlFileObj,
					outputXmlFilePath);

			LOGGER.log(Level.INFO, "XML file updated  \"" + outputXmlFilePath
					+ "\"");
		} catch (IOException e) {
			LOGGER
					.log(
							Level.SEVERE,
							"The updated xml file will not be saved because an error occured while creating a backup",
							e);
		}
	}

	/**
	 * Allows to create a backup if requested
	 * 
	 * @throws IOException
	 */
	private void createBackupIfRequested() throws IOException {
		if (m_createBackup) {
			File inputFile = new File(m_inputXmlFilePath);
			File backupFile = new File(m_backupXmlFilePath);

			try {
				FileUtils.copyFile(inputFile, backupFile);

				LOGGER.log(Level.INFO, "Backup created \""
						+ m_backupXmlFilePath + "\"");
			} catch (IOException e) {
				LOGGER.log(Level.SEVERE,
						"Unable to create a backup of the file \""
								+ m_inputXmlFilePath + "\"");
				throw e;
			}
		}
	}

	/**
	 * Updates the <T> object  
	 * @param xmlFileObj
	 */
	public void setXmlFileObj(T xmlFileObj) {
		m_xmlFileObj = xmlFileObj;
	}

	/**
	 * Retrieves the <T> object
	 * @return
	 */
	public T getXmlFileObj() {
		if (m_xmlFileObj == null) {
			try {
				loadXmlFileObject();
			} catch (JAXBException ex) {
				LOGGER.log(Level.SEVERE, null, ex);
			} catch (XMLStreamException ex) {
				LOGGER.log(Level.SEVERE, null, ex);
			} catch (FileNotFoundException ex) {
				LOGGER.log(Level.SEVERE, null, ex);
			}
		}

		return m_xmlFileObj;
	}

	/**
	 * Retrieves the path of the xml file
	 * @return
	 */
	public String getInputXmlFilePath() {
		return m_inputXmlFilePath;
	}

	/**
	 * Retrieves the path of the backup of the xml file
	 * @return
	 */
	public String getBackupXmlFilePath() {
		return m_backupXmlFilePath;
	}

	private JaxbXmlParser<T> getJaxbXmlParser() throws JAXBException {
		if (m_parser == null) {
			m_parser = new JaxbXmlParser<T>(m_xmlObjClazz,
					JaxbXmlParser.ENCODING_UTF8);
		}
		return m_parser;
	}
}
